package com.aiyan.edu.govern.gateway.filter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.metrics.MetricsEndpoint;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 基于CPU负载的动态限流过滤器工厂
 *
 * @author: zqzhou
 * @create: 2019/12/03 17:09
 **/
@Component
@Deprecated
public class RateLimitByCpuGatewayFilterFactory extends AbstractGatewayFilterFactory<RateLimitByCpuGatewayFilterFactory.Config> {

    @Autowired
    MetricsEndpoint metricsEndpoint;

    private static final String METRIC_NAME = "system.cpu.usage";
    private static final double MAX_USAGE = 0.50D;

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("byCpu");
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            if (!config.isByCpu()) {
                return chain.filter(exchange);
            }

            Double cpuUsage = metricsEndpoint.metric(METRIC_NAME, null)
                    .getMeasurements()
                    .stream()
                    .filter(Objects::nonNull)
                    .findFirst()
                    .map(MetricsEndpoint.Sample::getValue)
                    .filter(Double::isFinite)
                    .orElse(0.0D);

            System.out.println("system.cpu.usage: " + cpuUsage);

            if (cpuUsage > MAX_USAGE) {
                exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
                return exchange.getResponse().setComplete();
            }

            return chain.filter(exchange);
        };
    }

    public static class Config {
        // 控制是否开启
        private boolean byCpu;

        public Config() {
        }

        public boolean isByCpu() {
            return byCpu;
        }

        public void setByCpu(boolean byCpu) {
            this.byCpu = byCpu;
        }
    }
}
